package com.dadovicn.repo.primary.base;

import com.dadovicn.annoation.*;
import com.dadovicn.fx.ywb.qo.BaseQO;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.dsl.DatePath;
import com.querydsl.core.types.dsl.EntityPathBase;
import com.querydsl.core.types.dsl.StringPath;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

@Slf4j
public class BaseQueryDsl {
    @Resource
    @PersistenceContext
    private EntityManager entityManager;

    protected JPAQueryFactory queryFactory;

    @PostConstruct
    public void init() {
        this.queryFactory = new JPAQueryFactory(entityManager);
    }

    /**
     * 条件构建方法
     * @param bd 条件构建器
     * @param QO 查询对象
     * @param dslMap dsl 实体 map
     */
    protected void genCondition(BooleanBuilder bd, BaseQO QO, Map<String, EntityPathBase> dslMap) {
        Field[] QOFields = QO.getClass().getDeclaredFields();
        Arrays.asList(QOFields).stream().forEach(i -> {
            try {
                i.setAccessible(true);
                Object qoValue = i.get(QO);
                String filedName = i.getName();
                ForClass forClass =  i.getAnnotation(ForClass.class);
                String filedClassName = forClass.name();
                Class<?>[] classPairs  = forClass.classPairs();
                if(classPairs.length != 0) {
                    String classNameA =  classPairs[0].getSimpleName().substring(1);
                    String classNameB =  classPairs[1].getSimpleName().substring(1);
                    String paramsA = ((new StringBuilder()).append(Character.toLowerCase(classNameA.charAt(0))).append(classNameA.substring(1)).toString());
                    String paramsB = ((new StringBuilder()).append(Character.toLowerCase(classNameB.charAt(0))).append(classNameB.substring(1)).toString());
                    StringPath classA = (StringPath)classPairs[0].getDeclaredField(filedName)
                            .get(classPairs[0].getDeclaredConstructor(String.class).newInstance(paramsA));

                    StringPath classB = (StringPath)classPairs[1].getDeclaredField(filedName)
                            .get(classPairs[1].getDeclaredConstructor(String.class).newInstance(paramsB));
                    bd.and(classA.eq(classB));
                } else {
                    // 字段
                    if(qoValue != null) {
                        if(i.isAnnotationPresent(And.class)) {
                            StringPath prop = (StringPath)dslMap.get(filedClassName).getClass().getDeclaredField(filedName).get(dslMap.get(filedClassName));
                            if(prop.toString().equals("ywbJqCjjlb.cjzt")) {
                                bd.and(prop.eq((String)qoValue));
                            } else {
                                bd.and(prop.like('%' + (String)qoValue + '%'));
                            }
                        }

                        if(i.isAnnotationPresent(Date.class)) {
                            Date date = i.getAnnotation(Date.class);
                            DatePath prop = (DatePath) dslMap.get(filedClassName).getClass().getDeclaredField(date.value()).get(dslMap.get(filedClassName));
                            List<LocalDateTime> datePart = (List<LocalDateTime>)qoValue;
                            if(datePart.get(0).isEqual(datePart.get(1))) {
                                bd.and(prop.gt(datePart.get(0)));
                            } else {
                                bd.and(prop.gt(datePart.get(0))).and(prop.lt(datePart.get(1)));
                            }
                        }
                    }
                }

                i.setAccessible(false);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                log.error("没有为查询对象配置forclass注解");
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        });

    }
}